//
//  World.h
//  ComponentSystem
//
//  Created by Jeppe Nielsen on 9/24/14.
//  Copyright (c) 2014 Jeppe Nielsen. All rights reserved.
//

#pragma once
#include "GameComponent.hpp"
#include "GameObject.hpp"
#include "GameSystem.hpp"
#include <vector>
#include <memory>

class GameWorld {
public:
    
    friend class GameObject;
    
    GameWorld();
    ~GameWorld();
    
    GameObject* CreateObject();
    
    void Update(float dt);
    void Render();
    
    void DeleteAllObjects();
    
    const ObjectCollection& Objects();
    
    template<class T>
    T* AddSystem();
    
private:
    
    
    void UpdateRemovedObjects();
    void UpdateRemovedObject(GameObject* object);
    void UpdateChangedComponents();
    void UpdateRemovedComponents();
    
    void* AddComponent(GameObject* object, int componentID);
    void* AddComponent(GameObject* object, int componentID, GameObject* referenceObject);
    void RemoveComponent(GameObject* object, int componentID);
    void EnableComponent(GameObject* object, int componentID, bool enable);
    void* CloneComponent(GameObject* object, int componentID, GameObject* source);
    
    typedef std::vector<IGameComponentType*> ComponentTypes;
    ComponentTypes componentTypes;
    ComponentTypes changedComponentTypes;
    ComponentTypes removedComponentTypes;
    
    ObjectCollection activeObjects;
    ObjectCollection freeObjects;
    typedef std::set<GameObject*> RemovedObjects;
    RemovedObjects removedObjects;
    
    typedef std::vector<GameSystem*> Systems;
    Systems systems;
    friend class GameSystem;
    
    
};

//--------------------------- <GameWorld> -----------------------------

template<class T>
T* GameWorld::AddSystem() {
    T* system = new T();
    system->indexInList = (unsigned)systems.size();
    system->world = this;
    system->Initialize();
    systems.push_back(system);
    return system;
}

//--------------------------- </GameWorld> -----------------------------


//--------------------------- <GameObject> -----------------------------

template<class T>
T* GameObject::AddComponent() {
    return (T*)world->AddComponent(this, T::ID);
}

template<class T>
T* GameObject::AddComponent(GameObject* objectReference) {
    return (T*)world->AddComponent(this, T::ID, objectReference);
}

template<class T>
T* GameObject::GetComponent() {
    return (T*)components[T::ID];
}

template<class T>
void GameObject::RemoveComponent() {
    world->RemoveComponent(this, T::ID);
}

template<class T>
bool GameObject::IsComponentEnabled() {
    return (enabledComponents & T::Mask) == T::Mask;
}

template<class T>
void GameObject::EnableComponent(bool enable) {
    world->EnableComponent(this, T::ID, enable);
}

template<class T>
T* GameObject::CloneComponent(GameObject* source) {
    return (T*)world->CloneComponent(this, T::ID, source);
}

template<class T>
bool GameObject::IsComponentReference() {
    return !((ownedComponents & T::Mask) == T::Mask);
}

//--------------------------- </GameObject> -----------------------------


//--------------------------- <GameSystem> -----------------------------

template<class T>
void GameSystem::AddComponent() {
    IGameComponentType* type = world->componentTypes[T::ID];
    aspect |= type->mask;
    type->systems.push_back(this);
}

//--------------------------- </GameSystem> -----------------------------

